package beautiful.butterfly.drds.data_exchange.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.util.concurrent.Callable;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public final class RetryableTasks
{

    public static final Logger LOG = LoggerFactory.getLogger(RetryableTasks.class);

    public static final long MAX_SLEEP_MILLISECOND = 256 * 1000;

    /**
     * 重试次数工具方法.
     *
     * @param callable               实际逻辑
     * @param retryTimes             最大重试次数（>1）
     * @param sleepTimeInMilliSecond 运行失败后休眠对应时间再重试
     * @param exponential            休眠时间是否指数递增
     * @param <T>                    返回值类型
     * @return 经过重试的callable的执行结果
     */
    public static <T> T executeWithRetry(Callable<T> callable,
                                         int retryTimes,
                                         long sleepTimeInMilliSecond,
                                         boolean exponential) throws SQLException
    {
        RetryableTask retryableTask = new RetryableTask();
        return retryableTask.retryWhenDoTaskException(callable, retryTimes, sleepTimeInMilliSecond, exponential, null);
    }


    /**
     * 在外部线程执行并且重试。每次执行需要在timeoutMs内执行完，不然视为失败。
     * 执行异步操作的线程池从外部传入，线程池的共享粒度由外部控制。比如，HttpClientUtil共享一个线程池。
     * <p/>
     * 限制条件：仅仅能够在阻塞的时候interrupt线程
     *
     * @param <T>                    返回值类型
     * @param threadPoolExecutor     执行异步操作的线程池
     * @param callable               实际逻辑
     * @param retryTimes             最大重试次数（>1）
     * @param sleepTimeInMilliSecond 运行失败后休眠对应时间再重试
     * @param exponential            休眠时间是否指数递增
     * @param timeoutMs              callable执行超时时间，毫秒
     * @return 经过重试的callable的执行结果
     */
    public static <T> T asyncExecuteWithRetry(ThreadPoolExecutor threadPoolExecutor, Callable<T> callable,
                                              int retryTimes,
                                              long sleepTimeInMilliSecond,
                                              boolean exponential,
                                              long timeoutMs) throws Exception
    {
        RetryableTask retryableTask = new AsyncRetryableTask(timeoutMs, threadPoolExecutor);
        return retryableTask.retryWhenDoTaskException(callable, retryTimes, sleepTimeInMilliSecond, exponential, null);
    }

    /**
     * 创建异步执行的线程池。特性如下：
     * core大小为0，初始状态下无线程，无初始消耗。
     * max大小为5，最多五个线程。
     * 60秒超时时间，闲置超过60秒线程会被回收。
     * 使用SynchronousQueue，任务不会排队，必须要有可用线程才能提交成功，否则会RejectedExecutionException。
     *
     * @return 线程池
     */
    public static ThreadPoolExecutor createThreadPoolExecutor()
    {
        return new ThreadPoolExecutor(0, 5,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
    }


}
